﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

namespace LCSFlashCards
{
    public enum BoxMode
    {
        StudyMode,
        ReviewMode
    }

    [Serializable()]
    public class Box<T> : ISerializable
    {
        public event EventHandler<BoxStudyFinishedEventArgs> BoxStudyFinished;

        public BoxMode CurrentBoxMode { get; set; }
        public int CompartmentCursor { get; set; }

        private List<Compartment<T>> compartments = new List<Compartment<T>>();
        private List<Card<T>> archive = new List<Card<T>>();

        public int BoxSize 
        {
            get
            {
                return compartments.Count;
            }
        }
        public Compartment<T> this[int index]
        {
            get { return compartments[index]; }
            set { compartments[index] = value; }
        }
        public Box()
        {
            InitializeBox(5);
        }
        public Box(int boxSize)
        {
            InitializeBox(boxSize);
        }
        private void InitializeBox(int size)
        {
            for(int i = 0; i < size; i++)
            {
                Compartment<T> newComp = new Compartment<T>(i);
                //newComp.CompartmentFinished += 
                compartments.Add(newComp);
            }
            this.CompartmentCursor = BoxSize - 1;
        }
        public void AddNewCard(Card<T> card)
        {
            if (BoxSize == 0)
                throw new Exception("اندازه جعبه لایتنر صفر است");
            compartments[0].AddCard(card);
        }
        public Card<T> GetNextCard()
        {
            Card<T> nextCard = compartments[this.CompartmentCursor].GetNextCard();
            if(nextCard == null)
            {
                if (CompartmentCursor == 0)
                {
                    this.CurrentBoxMode = BoxMode.ReviewMode;
                    StopStudy();                       
                    return null;
                }
                else
                {
                    CompartmentCursor--;
                    return GetNextCard();
                }
            }
            return nextCard;
        }
        public void StopStudy()
        {
            BoxStudyFinishedEventArgs bsfea = new BoxStudyFinishedEventArgs();
            foreach(Compartment<T> comp in compartments)
                while (comp.tempCards.Count > 0)
                {
                    if (comp.tempCards[0].Tag == CardTag.Failed)
                    {
                        AddNewCard(comp.tempCards[0]);
                        bsfea.NumberOfFailedCards++;
                        bsfea.TotalNumberOfCardsStudied++;
                    }
                    else if (comp.tempCards[0].Tag == CardTag.Successful)
                    {
                        if (comp.CompartmentNumber == BoxSize - 1)
                            archive.Add(comp.tempCards[0]);
                        else
                            compartments[comp.CompartmentNumber + 1].AddCard(comp.tempCards[0]);
                        bsfea.NumberOfSuccessfulCards++;
                        bsfea.TotalNumberOfCardsStudied++;
                    }
                    comp.tempCards.RemoveAt(0);
                }
            if (BoxStudyFinished != null)
                BoxStudyFinished(this, bsfea);
        }
        public Box(SerializationInfo info, StreamingContext context)
        {
            this.CurrentBoxMode = (BoxMode)info.GetValue("CurrentBoxMode", typeof(BoxMode));
            this.CompartmentCursor = (int)info.GetValue("CompartmentCursor", typeof(int));
            this.compartments = (List<Compartment<T>>)info.GetValue("Compartments", typeof(List<Compartment<T>>));
            this.archive = (List<Card<T>>)info.GetValue("Archive", typeof(List<Card<T>>));
        }
        public void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.AddValue("CurrentBoxMode", CurrentBoxMode);
            info.AddValue("CompartmentCursor", CompartmentCursor);
            info.AddValue("Compartments", compartments);
            info.AddValue("Archive", archive);
        }
        public int Count()
        {
            int count = 0;
            foreach (Compartment<T> c in this.compartments)
                count += c.CountCards();
            return count;
        }
        public int CountTrue()
        {
            int count = 0;
            foreach (Compartment<T> c in this.compartments)
                count += c.CountTrueCards();
            return count;
        }
        public int CountFail()
        {
            int count = 0;
            foreach (Compartment<T> c in this.compartments)
                count += c.CountFailedCards();
            return count;
        }
        public int CountFresh()
        {
            int count = 0;
            foreach (Compartment<T> c in this.compartments)
                count += c.CountFreshCards();
            return count;
        }
        public int CountDelayed()
        {
            int count = 0;
            foreach (Compartment<T> c in this.compartments)
                count += c.CountDelayedCards();
            return count;
        }
        public int CountArchived()
        {
            return archive.Count;
        }
        public int GetCurrentProgress()
        {
            return 100 * archive.Count / Count();
        }
    }
}
